package com.binc.testspring.study.nio.netty.protobuf.demo;

import com.google.protobuf.TextFormat;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * FileName: My_server_handler   自定义的服务端handler     继承netty的ChannelInboundHandlerAdapter
 *      需要继承netty 规定好的某个HandlerAdapter(规范), 这时我们自定义一个Handler , 才能称为一个handler
 * Autho: binC
 * Date:  2022/4/19 14:49
 */
@Slf4j
// public class My_server_handler extends ChannelInboundHandlerAdapter {
    //如果是 继承ChannelInboundHandlerAdapter  那么我们就需要重写ChannelRead方法,方法中的消息就是 object类型的;我们需要将object msg 强制类型转换成具体的类型 如:MyDataInfo.MyMessage  String   ByteBuf 等

public class My_server_handler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> {
    //如果是 SimpleChannelInboundHandler  那么我们就需要重写ChannelRead0方法,方法中的消息就是 服务端配置的数据类型了
    /**
     * 读取数据事件(这里我们可以读取客户端发送的消息)
     *
     *     1. ChannelHandlerContext ctx:上下文对象, 含有 管道pipeline , 通道channel, 地址
     *     2. Object msg: 就是客户端发送的数据 默认Object
     *
     * @param ctx  上下文   这里能获取到 pipeline   也能获取到channel
     * @param msg  真正的消息
     */
   // @Override  因为不是继承的ChannelInboundHandlerAdapter  所以这里不用重写channelRead方法
   //  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   //      // super.channelRead(ctx, msg);
   //
   //      log.info("<<<<<<=====服务器端读取线程:"+Thread.currentThread().getName()+" channel:"+ctx.channel());
   //      log.info("<<<<<<=====服务器端  上下文ctx:"+ctx);
   //      MyDataInfo.MyMessage myMessage = (MyDataInfo.MyMessage) msg;
   //      MyDataInfo.MyMessage.DataType dataType = myMessage.getDataType();
   //      if (dataType == MyDataInfo.MyMessage.DataType.StudentType) {
   //          MyDataInfo.Student student = myMessage.getStudent();
   //          System.out.println("<<<<<服务端收到的是学生信息:" + student.toString());
   //      } else {
   //          MyDataInfo.Worker worker = myMessage.getWorker();
   //          System.out.println("<<<<<服务端收到的是工人信息:" + worker.toString());
   //
   //      }
   //
   //      log.info("===========================================================================");
   //
   //  }

    /**
     因为继承的是SimpleChannelInboundHandler  所以重写channelRead0方法,信息对象不用进行强制类型转换了
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MyDataInfo.MyMessage msg) throws Exception {
        log.info("<<<<<<=====服务器端读取线程:"+Thread.currentThread().getName()+" channel:"+ctx.channel());
        log.info("<<<<<<=====服务器端  上下文ctx:"+ctx);
        MyDataInfo.MyMessage.DataType dataType = msg.getDataType();
        if (dataType == MyDataInfo.MyMessage.DataType.StudentType) {
            MyDataInfo.Student student = msg.getStudent();
            System.out.println("<<<<<服务端收到的是学生信息:" + student.toString());  // 如果直接toString 会显示字节信息   而不是汉字
            System.out.println("<<<<<服务端收到的是学生信息:" + student.getName()); // get单个属性  显示的就是汉字了
            System.out.println("<<<<<服务端收到的是学生信息:" + TextFormat.printToUnicodeString(student) ); // 如果就是想显示整个对象,直接用这个方法
        } else {
            MyDataInfo.Worker worker = msg.getWorker();
            System.out.println("<<<<<服务端收到的是工人信息:" + worker.toString());
            System.out.println("<<<<<服务端收到的是工人信息:" + worker.getName());

            System.out.println("<<<<<服务端收到的是工人信息:" + TextFormat.printToUnicodeString(worker) );

        }

        log.info("===========================================================================");
    }

    /**
     * 数据读取完毕
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // super.channelReadComplete(ctx);

        //  我们模拟读取完消息后,要给客户端回一个消息
        //writeAndFlush 是 write + flush
        //将数据写入到缓存，并刷新
        //一般讲，我们对这个发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("客户端你好,你的消息我收到了",CharsetUtil.UTF_8));
    }

    /**
     *发生异常的话,关闭通道
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // super.exceptionCaught(ctx, cause);
        ctx.close();
    }
}
